package com.linkstec.util;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HttpClientHelper {
	private static final Logger logger = LogManager.getLogger();
	// 30min超时时间
	public static int SOCKET_TIMEOUT = 30 * 60 * 1000;
	// 等待结果返回时间
	public static int CONNECTION_REQUEST_TIMEOUT = 30 * 60 * 1000;
	// HTTPConnection最大连接数
	public static int MAX_CONN = 40;
	// private static final Logger logger = LoggerFactory
	// .getLogger(HttpClientHelper.class);
	private static CloseableHttpClient httpclient = null;
	private static ResponseHandler<String> responseHandler = new ResponseHandler<String>() {

		@Override
		public String handleResponse(final HttpResponse response)
				throws ClientProtocolException, IOException {
			int status = response.getStatusLine().getStatusCode();
			if (status >= 200 && status < 300) {
				HttpEntity entity = response.getEntity();
				return entity != null ? EntityUtils.toString(entity) : null;
			} else {
				throw new ClientProtocolException(
						"Unexpected response status: " + status);
			}
		}
	};

	static {
		/**
		 * socketTimeout,两台服务器之前没有通信的超时时间(exp:下载文件请求，需要很长时间，但是由于两端之间一直在通信，
		 * 所以并不算超时)。 官网解释：Defines the socket timeout (SO_TIMEOUT) in
		 * milliseconds, which is the timeout for waiting for data or, put
		 * differently, a maximum period inactivity between two consecutive data
		 * packets).
		 * 
		 * connectionTimeout请求与url连接的超时时间，官网解释：Determines the timeout in
		 * milliseconds until a connection is established.
		 * 
		 * connectionRequestTimeout连接，等待返回结果的超时时间。官网解释：Returns the timeout in
		 * milliseconds used when requesting a connection from the connection
		 * manager.
		 */
		RequestConfig defaultRequestConfig = RequestConfig.custom()
				.setSocketTimeout(SOCKET_TIMEOUT).setConnectTimeout(10 * 1000)
				.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
				.build();
		try {

			SSLContext sslContext = SSLContexts.custom()
					.loadTrustMaterial(new TrustStrategy() {

						@Override
						public boolean isTrusted(X509Certificate[] chain,
								String authType) throws CertificateException {

							return true;
						}
					}).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslContext, new String[] { "TLSv1" }, null,
					new HostnameVerifier() {
						@Override
						public boolean verify(String arg0, SSLSession arg1) {
							return true;
						}
					});
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
					.<ConnectionSocketFactory> create()
					.register("http", PlainConnectionSocketFactory.INSTANCE)
					.register("https", sslsf).build();

			PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
					socketFactoryRegistry);
			ConnectionConfig connectionConfig = ConnectionConfig.custom()
					.setCharset(Consts.UTF_8).build();
			cm.setDefaultConnectionConfig(connectionConfig);
			cm.setMaxTotal(MAX_CONN);

			httpclient = HttpClients.custom()
					.setDefaultRequestConfig(defaultRequestConfig)
					.setConnectionManager(cm).build();

		} catch (Exception e) {
			logger.error("", e);
		}

	}

	public static void closeHttpClient() {
		if (httpclient != null) {
			try {
				httpclient.close();
			} catch (IOException e) {
				logger.error("", e);
			}
		}
	}

	public static String httpGet(String url) {
		HttpGet httpget = new HttpGet(url);

		String responseBody = null;
		try {
			responseBody = httpclient.execute(httpget, responseHandler);
		} catch (Exception e) {
			logger.error("", e);
		}
		return responseBody;
	}

	/**
	 * 
	 * @param url
	 * @param data
	 * @return
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String httpPost(String url, Map<String, String> data)
			throws ClientProtocolException, IOException {
		HttpPost httppost = new HttpPost(url);
		if (data != null && data.size() > 0) {
			List<NameValuePair> list = new ArrayList<NameValuePair>();
			Iterator<Entry<String, String>> iterator = data.entrySet()
					.iterator();
			while (iterator.hasNext()) {
				Entry<String, String> elem = (Entry<String, String>) iterator
						.next();
				list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
			}
			if (list.size() > 0) {
				UrlEncodedFormEntity entity = null;
				entity = new UrlEncodedFormEntity(list, "UTF-8");
				httppost.setEntity(entity);
			}
		}
		String responseBody = null;
		responseBody = httpclient.execute(httppost, responseHandler);
		logger.debug(responseBody);
		return responseBody;
	}

}
